package com.liyong.pullorder.sdk;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.liyong.pullorder.sdk.autoconfigure.PullOrderSdkProperties;
import com.liyong.pullorder.sdk.client.auth.AuthStrategy;
import com.liyong.pullorder.sdk.dto.PlatformOrderResponse;
import com.liyong.pullorder.sdk.dto.StandardOrderDto;
import com.liyong.pullorder.sdk.exception.AuthException;
import com.liyong.pullorder.sdk.exception.DataParseException;
import com.liyong.pullorder.sdk.exception.NetworkException;
import com.liyong.pullorder.sdk.exception.PullOrderException;
import com.liyong.pullorder.sdk.parser.ParserStrategy;
import com.liyong.pullorder.sdk.retry.RetryConfig;
import com.liyong.pullorder.sdk.sentinel.SentinelConfig;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 葡萄味的萝卜
 * @date 2025/10/21 09:57
 * 拉单SDK核心服务类
 * 核心作用：整合所有组件，提供统一的拉单服务入口，作为公司供应链体系的唯一订单入口
 * 设计目标：将新平台接入周期从2-3人周缩短至0.5人周，效率提升70%以上
 *
 * 处理能力：日均处理10万+订单数据请求，为下游系统提供稳定、洁净的数据源
 * 集成特性：
 * - 统一认证管理：支持OAuth2、API Key等多种认证方式
 * - 多格式解析：支持JSON/XML格式订单数据解析
 * - 智能重试：指数退避重试机制应对网络不稳定
 * - 限流降级：Sentinel集成保障系统稳定性
 * - 监控告警：实时通知拉单失败或数据异常
 */
@Slf4j
public class PullOrderSdkService {
     private final PullOrderSdkProperties properties;
     private final Map<String, AuthStrategy> authStrategies;
     private final Map<String, ParserStrategy> parserStrategies;
     private final SentinelConfig sentinelConfig;
     private final RetryConfig retryConfig;
     private final RestTemplate restTemplate;

     /**
      * 构造函数 - 依赖注入所有必要组件
      */
    public PullOrderSdkService(PullOrderSdkProperties properties,
                               RestTemplate restTemplate,
                               List<AuthStrategy> authStrategies,
                               List<ParserStrategy> parserStrategies,
                               SentinelConfig sentinelConfig,
                               RetryConfig retryConfig) {
        this.properties = properties;
        this.restTemplate = restTemplate;
        this.sentinelConfig = sentinelConfig;
        this.retryConfig = retryConfig;
         // 将策略列表转换为Map，便于快速查找
         this.authStrategies = authStrategies.stream()
                 .collect(Collectors.toMap(AuthStrategy::getType, strategy -> strategy));
         this.parserStrategies = parserStrategies.stream()
                 .collect(Collectors.toMap(ParserStrategy::getSupportedFormat, strategy -> strategy));

        log.info("拉单SDK服务初始化完成 - 支持认证方式: {}, 支持解析格式: {}",
                this.authStrategies.keySet(), this.parserStrategies.keySet());
    }

    /**
     * 统一拉单入口方法
     * 核心流程：认证 -> 请求 -> 解析 -> 清洗 -> 返回
     * 容错机制：重试 + 限流 + 降级 + 监控
     *
     * @param platformCode 平台编码，如：HUAWEI、HONOR、ZJMOBILE
     * @return 标准化订单响应，包含订单列表和状态信息
     */
    @Retryable(
            value = {NetworkException.class, DataParseException.class},
            maxAttempts = 3,
            backoff = @Backoff(delay = 1000, multiplier = 2.0)
    )
    @SentinelResource(
            value = "pullOrder",
            blockHandler = "handlePullOrderBlock",
            fallback = "handlePullOrderFallback",
            blockHandlerClass = SentinelConfig.class,
            fallbackClass = SentinelConfig.class
    )
    public PlatformOrderResponse pullOrders(String platformCode) {
        log.info("开始拉取平台订单 - 平台: {}", platformCode);

        // 1. 参数校验和配置获取
        PullOrderSdkProperties.PlatformConfig platformConfig = validateAndGetConfig(platformCode);

        try {
            // 2. 构建认证请求
            HttpEntity<String> requestEntity = buildRequestEntity(platformConfig);

            // 3. 执行HTTP请求
            String responseData = executeHttpRequest(platformConfig, requestEntity);

            // 4. 解析响应数据
            List<StandardOrderDto> orders = parseResponseData(responseData, platformConfig);

            // 5. 返回成功结果
            PlatformOrderResponse response = PlatformOrderResponse.success(orders);
            log.info("拉单成功 - 平台: {}, 订单数量: {}", platformCode, orders.size());

            return response;

        } catch (AuthException e) {
            // 认证异常，不可重试，需要人工干预
            log.error("拉单认证失败 - 平台: {}, 错误: {}", platformCode, e.getMessage());
            return PlatformOrderResponse.failure("AUTH_FAILED", "认证失败: " + e.getMessage());

        } catch (DataParseException e) {
            // 数据解析异常，记录原始数据用于排查
            log.error("拉单数据解析失败 - 平台: {}, 原始数据: {}",
                    platformCode, e.getMaskedRawData());
            throw e; // 抛出以触发重试

        } catch (NetworkException e) {
            // 网络异常，可重试
            log.warn("拉单网络异常 - 平台: {}, URL: {}, 错误: {}",
                    platformCode, e.getRequestUrl(), e.getMessage());
            throw e; // 抛出以触发重试

        } catch (Exception e) {
            // 其他异常
            log.error("拉单系统异常 - 平台: {}, 错误: {}", platformCode, e.getMessage(), e);
            return PlatformOrderResponse.failure("SYSTEM_ERROR", "系统异常: " + e.getMessage());
        }
    }

    /**
     * 参数校验和配置获取
     * 作用：验证平台配置有效性，确保拉单参数正确
     */
    private PullOrderSdkProperties.PlatformConfig validateAndGetConfig(String platformCode) {
        if (platformCode == null || platformCode.trim().isEmpty()) {
            throw new IllegalArgumentException("平台编码不能为空");
        }

        PullOrderSdkProperties.PlatformConfig platformConfig =
                properties.getPlatforms().get(platformCode);

        if (platformConfig == null) {
            throw new IllegalArgumentException("未找到平台配置: " + platformCode);
        }

        if (platformConfig.getBaseUrl() == null || platformConfig.getBaseUrl().trim().isEmpty()) {
            throw new IllegalArgumentException("平台基础URL不能为空: " + platformCode);
        }

        if (platformConfig.getAuth() == null) {
            throw new IllegalArgumentException("平台认证配置不能为空: " + platformCode);
        }

        if (platformConfig.getParser() == null) {
            throw new IllegalArgumentException("平台解析配置不能为空: " + platformCode);
        }

        return platformConfig;
    }

    /**
     * 构建请求实体
     * 核心功能：应用认证策略，设置请求头，准备HTTP请求
     */
    private HttpEntity<String> buildRequestEntity(PullOrderSdkProperties.PlatformConfig platformConfig) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        // 设置平台自定义请求头
        if (platformConfig.getHeaders() != null) {
            platformConfig.getHeaders().forEach(headers::set);
        }

        // 应用认证策略
        applyAuthentication(headers, platformConfig);

        return new HttpEntity<>(null, headers);
    }

    /**
     * 应用认证策略
     * 设计模式：策略模式，根据配置自动选择认证方式
     */
    private void applyAuthentication(HttpHeaders headers, PullOrderSdkProperties.PlatformConfig platformConfig) {
        String authType = platformConfig.getAuth().getType();
        AuthStrategy authStrategy = authStrategies.get(authType);

        if (authStrategy == null) {
            throw new AuthException("不支持的认证类型: " + authType, platformConfig.getBaseUrl());
        }

        try {
            authStrategy.applyAuth(headers, platformConfig.getAuth().getConfig());
            log.debug("应用认证成功 - 类型: {}, 平台: {}", authType, platformConfig.getBaseUrl());
        } catch (Exception e) {
            throw new AuthException("认证应用失败: " + e.getMessage(), platformConfig.getBaseUrl());
        }
    }

    /**
     * 执行HTTP请求
     * 容错特性：连接池管理、超时控制、重试机制
     */
    private String executeHttpRequest(PullOrderSdkProperties.PlatformConfig platformConfig,
                                      HttpEntity<String> requestEntity) {
        String apiUrl = buildApiUrl(platformConfig);

        try {
            log.debug("执行HTTP请求 - URL: {}", apiUrl);

            ResponseEntity<String> response = restTemplate.exchange(
                    apiUrl, HttpMethod.GET, requestEntity, String.class);

            if (response.getStatusCode() == HttpStatus.OK) {
                String responseData = response.getBody();
                log.debug("HTTP请求成功 - URL: {}, 数据长度: {}", apiUrl,
                        responseData != null ? responseData.length() : 0);
                return responseData;
            } else {
                log.error("HTTP请求失败 - URL: {}, 状态码: {}", apiUrl, response.getStatusCode());
                throw new NetworkException("HTTP请求失败，状态码: " + response.getStatusCode(),
                        platformConfig.getBaseUrl(), apiUrl);
            }

        } catch (org.springframework.web.client.ResourceAccessException e) {
            // 网络连接异常
            throw new NetworkException("网络连接异常: " + e.getMessage(), platformConfig.getBaseUrl(), apiUrl);
        } catch (org.springframework.web.client.HttpClientErrorException e) {
            // 4xx 客户端错误
            log.error("HTTP客户端错误 - URL: {}, 状态码: {}, 响应: {}",
                    apiUrl, e.getStatusCode(), e.getResponseBodyAsString());
            throw new PullOrderException("客户端错误: " + e.getMessage(),
                    "CLIENT_ERROR", platformConfig.getBaseUrl());
        } catch (org.springframework.web.client.HttpServerErrorException e) {
            // 5xx 服务端错误
            log.error("HTTP服务端错误 - URL: {}, 状态码: {}", apiUrl, e.getStatusCode());
            throw new NetworkException("服务端错误: " + e.getMessage(), platformConfig.getBaseUrl(), apiUrl);
        }
    }

    /**
     * 构建API请求URL
     * 扩展性：支持参数化URL，便于不同平台的API差异
     */
    private String buildApiUrl(PullOrderSdkProperties.PlatformConfig platformConfig) {
        // 这里可以添加时间范围参数、分页参数等
        // 例如：platformConfig.getBaseUrl() + "?startTime=xxx&endTime=xxx"
        return platformConfig.getBaseUrl();
    }

    /**
     * 解析响应数据
     * 核心功能：根据平台配置选择解析器，完成数据标准化
     */
    private List<StandardOrderDto> parseResponseData(String responseData,
                                                     PullOrderSdkProperties.PlatformConfig platformConfig) {
        if (responseData == null || responseData.trim().isEmpty()) {
            log.warn("响应数据为空 - 平台: {}", platformConfig.getBaseUrl());
            return java.util.Collections.emptyList();
        }

        String dataFormat = platformConfig.getParser().getType();
        ParserStrategy parserStrategy = parserStrategies.get(dataFormat);

        if (parserStrategy == null) {
            throw new DataParseException("不支持的数格式: " + dataFormat, platformConfig.getBaseUrl());
        }

        try {
            List<StandardOrderDto> orders = parserStrategy.parse(responseData, platformConfig);

            // 设置平台编码
            orders.forEach(order -> {
                order.setPlatformCode(extractPlatformCode(platformConfig.getBaseUrl()));
                order.setCreateTime(new java.util.Date());
                order.setUpdateTime(new java.util.Date());
            });

            return orders;

        } catch (DataParseException e) {
            // 重新包装异常，保留原始数据
            throw new DataParseException(e.getMessage(), e.getCause(),
                    platformConfig.getBaseUrl(), responseData);
        } catch (Exception e) {
            throw new DataParseException("数据解析异常: " + e.getMessage(), e,
                    platformConfig.getBaseUrl(), responseData);
        }
    }

    /**
     * 从URL中提取平台编码
     */
    private String extractPlatformCode(String baseUrl) {
        // 简化实现，实际应该从配置中获取
        if (baseUrl.contains("huawei")) return "HUAWEI";
        if (baseUrl.contains("honor")) return "HONOR";
        if (baseUrl.contains("zjmobile")) return "ZJMOBILE";
        return "UNKNOWN";
    }

    /**
     * 批量拉单方法 - 支持同时拉取多个平台订单
     * 应用场景：定时任务批量拉取所有平台订单
     */
    public Map<String, PlatformOrderResponse> pullOrdersBatch(List<String> platformCodes) {
        log.info("开始批量拉单 - 平台数量: {}", platformCodes.size());

        return platformCodes.stream()
                .collect(Collectors.toMap(
                        platformCode -> platformCode,
                        this::pullOrders,
                        (existing, replacement) -> existing
                ));
    }

    /**
     * 分页拉单方法 - 支持分页拉取大量订单
     * 应用场景：平台订单量较大，需要分页拉取
     */
    public PlatformOrderResponse pullOrdersWithPagination(String platformCode,
                                                          int page, int pageSize) {
        log.info("开始分页拉单 - 平台: {}, 页码: {}, 页大小: {}", platformCode, page, pageSize);

        // 实现分页逻辑，构建带分页参数的URL
        // 这里需要根据具体平台的API设计实现

        return pullOrders(platformCode); // 简化实现
    }

    /**
     * 健康检查方法 - 检查平台连接状态
     * 应用场景：系统监控、平台可用性检查
     */
    public boolean healthCheck(String platformCode) {
        try {
            PullOrderSdkProperties.PlatformConfig platformConfig =
                    properties.getPlatforms().get(platformCode);

            if (platformConfig == null) {
                log.warn("健康检查失败 - 未找到平台配置: {}", platformCode);
                return false;
            }

            // 构建简单的健康检查请求
            HttpEntity<String> requestEntity = buildRequestEntity(platformConfig);
            String healthCheckUrl = platformConfig.getBaseUrl().replace("/orders", "/health");

            ResponseEntity<String> response = restTemplate.exchange(
                    healthCheckUrl, HttpMethod.GET, requestEntity, String.class);

            return response.getStatusCode() == HttpStatus.OK;

        } catch (Exception e) {
            log.warn("健康检查异常 - 平台: {}, 错误: {}", platformCode, e.getMessage());
            return false;
        }
    }

    /**
     * 获取支持的平台列表
     * 应用场景：动态展示可拉单平台
     */
    public List<String> getSupportedPlatforms() {
        return new java.util.ArrayList<>(properties.getPlatforms().keySet());
    }

    /**
     * 获取平台配置信息
     * 应用场景：配置管理、监控展示
     */
    public PullOrderSdkProperties.PlatformConfig getPlatformConfig(String platformCode) {
        return properties.getPlatforms().get(platformCode);
    }
}
